package cn.sunxiansheng.seckill.token.filter;

import cn.sunxiansheng.redis.utils.RString;
import cn.sunxiansheng.redis.utils.SunRaysLua;
import cn.sunxiansheng.tool.response.SunRaysServletResponse;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;

/**
 * Description: 对Token进行校验
 *
 * @Author sun
 * @Create 2025/1/8 16:09
 * @Version 1.0
 */
@Slf4j
public class TokenFilter implements Filter {

    /**
     * 存放Token的ThreadLocal
     */
    public static final ThreadLocal<String> TOKEN_THREAD_LOCAL = new ThreadLocal<>();

    private RString rString;

    /**
     * 在注册过滤器的时候传入
     *
     * @param rString
     */
    public TokenFilter(RString rString) {
        this.rString = rString;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Token Filter");
        // 1.从请求头中获取Token
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        // 这个Authorization是前端放token的位置
        String token = httpRequest.getHeader("Authorization");
        // 2.当获取不到Token的时候，告诉前端
        if (token == null) {
            SunRaysServletResponse.writeFail((HttpServletResponse) servletResponse, 401, "请在请求头中携带订单Token！");
            // 注意，这个return非常重要，因为一旦放行了，就可能再次调用getWriter() 或 getOutputStream()导致报错
            return;
        }
        // 3.校验token，使用lua脚本判断key是否存在，如果存在则删除并返回该键
        String res = rString.executeLuaScript(SunRaysLua.GET_AND_DELETE, String.class, Collections.singletonList(token));
        // 如果结果是空，说明token不存在
        if (res == null) {
            SunRaysServletResponse.writeFail((HttpServletResponse) servletResponse, 401, "Token不存在！");
            return;
        }
        // 如果Token存在，就放到ThreadLocal中，方便在buy方法中获取，并存到数据库中
        TOKEN_THREAD_LOCAL.set(token);

        // 放行请求，继续后续的过滤器链
        filterChain.doFilter(servletRequest, servletResponse);

        // 清理ThreadLocal
        TOKEN_THREAD_LOCAL.remove();
    }
}